home *** CD-ROM | disk | FTP | other *** search
- /* File: sound.c
- * Created: 20-10-95
- * Updated: 30-12-95
- * Version: 1.0
- * Project: Clicker
- * Owner: Jeroen Vermeulen
- * Requirements: KickStart V39+
- * Legal: PD
- * Status: Release
- */
-
- #include <math.h>
-
- #include <proto/exec.h>
- #include <exec/devices.h>
- #include <exec/memory.h>
- #include <devices/audio.h>
- #include <proto/alib.h>
-
- #include "main.h"
- #include "sound.h"
- #include "prefs.h"
-
-
- static STRPTR
- AllocFailChipMem = "Not enough CHIP memory!\n",
- AllocFailPubMem = "Not enough PUBLIC memory!\n",
- OpenFailAudioDev = "Can't open audio.device\n";
-
- /* Here's our basic built-in sample. It's a very crude sine wave but it should
- * do for those very short intervals.
- * NOTE: SAMPLELENGTH must be defined to the length of this array!
- */
- static signed char Sample[SAMPLELENGTH] = { 0, 60, 100, 127, 100, 60,
- 0, -60, -100, -127, -100, -60 };
-
- /* Allocation priority array for sound channels. Don't see the point really, as
- * we're only asking for a single lousy sound channel. Oh well, audio.device
- * seems to insist that we provide this.
- */
- static unsigned char SoundChannels[] = { 2,1,4,8 };
-
-
- /* CreateSample():
- * Open audio device and sample. An IOAudio structure is returned unless either
- * an error occurs or the error string was already non-NULL before the call.
- */
- struct IOAudio *CreateSample(STRPTR *const error)
- {
- struct IOAudio *soundrequest = NULL;
- struct IORequest *plainrequest;
- struct MsgPort *Reply;
-
- if ((Reply = CreateMsgPort()))
- {
- plainrequest = CreateIORequest(Reply,sizeof(struct IOAudio));
- soundrequest = (struct IOAudio *)plainrequest;
-
- if (soundrequest)
- {
- soundrequest->ioa_Data = SoundChannels;
- soundrequest->ioa_Length = 4;
- plainrequest->io_Command = ADCMD_ALLOCATE;
- plainrequest->io_Flags = ADIOF_NOWAIT;
-
- if (OpenDevice("audio.device",0,plainrequest,0) == 0)
- {
- UBYTE *SampleMem;
- /* --- */
- SampleMem = (UBYTE *)AllocMem(SAMPLELENGTH,MEMF_PUBLIC|MEMF_CHIP);
-
- if (SampleMem)
- {
- CopyMem(Sample,SampleMem,SAMPLELENGTH);
- plainrequest->io_Flags = ADIOF_PERVOL|IOF_QUICK;
- plainrequest->io_Command = CMD_WRITE;
- soundrequest->ioa_Data = SampleMem;
- soundrequest->ioa_Length = SAMPLELENGTH;
- }
- else *error = AllocFailChipMem;
- }
- else *error = OpenFailAudioDev;
- }
- else *error = AllocFailPubMem;
- }
- else *error = AllocFailMsgPort;
-
- if (*error)
- {
- DeleteSample(soundrequest);
- soundrequest = NULL;
- }
-
- return soundrequest;
- }
-
-
- /* Destroy sample and free all resources allocated with it. This function is
- * overly robust so it can be used from within CreateSample() in case of an
- * error.
- */
- void DeleteSample(struct IOAudio *const soundrequest)
- {
- if (soundrequest)
- {
- struct IORequest *const plainrequest = &soundrequest->ioa_Request;
- if (plainrequest->io_Message.mn_ReplyPort)
- {
- CloseDevice(plainrequest);
- DeleteMsgPort(plainrequest->io_Message.mn_ReplyPort);
- }
- if (soundrequest->ioa_Data) FreeMem(soundrequest->ioa_Data,SAMPLELENGTH);
- DeleteIORequest(plainrequest);
- }
- }
-
-
- /* KeyClick():
- * Make key-click noise. The soundrequest pointer is assumed to be valid and
- * non-NULL, and point at a properly initialized IOAudio structure.
- */
- void KeyClick(struct IOAudio *const soundrequest)
- {
- if (ClickPrefs.newsettings)
- {
- ClickPrefs.newsettings = FALSE;
- soundrequest->ioa_Period = ClickPrefs.period;
- soundrequest->ioa_Volume = ClickPrefs.volume;
- soundrequest->ioa_Cycles = ClickPrefs.cycles;
- soundrequest->ioa_Request.io_Flags = ADIOF_PERVOL | IOF_QUICK;
- }
- BeginIO(&soundrequest->ioa_Request);
- WaitIO(&soundrequest->ioa_Request);
- }
-
-
- /* SliderToHertz():
- * Converts a prefs window slider position (between -5*12 and 4*12) to a
- * frequency in Hertz, based on a twelve-tone octave centered at the 440 Hz A.
- */
- LONG SliderToHertz(const struct Gadget *const dum, const WORD sliderpos)
- {
- /* Frequency is 440 * 2^(n/12). Note that left-shift cannot be used here.
- */
- return (LONG)(440 * pow((double)2,sliderpos/(double)12));
- }
-
-
- /* HertzToPeriod():
- * Converts human-readable pitch in Hertz to period length suitable for use by
- * audio.device. As a rule, HertzToPeriod(SliderToHertz(S)) is equivalent to
- * SliderToPeriod(S).
- */
- UWORD HertzToPeriod(const LONG Hertz)
- {
- /* Period should be computed from frequency f as 10^9 / (279.365 * s * f),
- * where s is the sample length. With proper constant folding, this should
- * compile to (C/Hertz) where C is a constant.
- */
- return (UWORD)((1000000000/(279.365*SAMPLELENGTH))/Hertz);
- }
-
-
- /* PeriodToHertz():
- * Converts audio.device period length to human-readable pitch in Hertz. This
- * is the inverse of HertzToPeriod().
- */
- LONG PeriodToHertz(const UWORD period)
- {
- /* Pitch in Hertz is computed from period f as 279.365 * s * p / 10^9, where s
- * is sample length.
- */
- return (LONG)((279.365 * SAMPLELENGTH / 1000000000) * period);
- }
-
-
- /* SliderToPeriod():
- * Converts a prefs window slider position (between 0 and 9*12) to a period
- * length (in units of 279.365 nanoseconds) suitable for use by audio.device.
- */
- UWORD SliderToPeriod(const WORD sliderpos)
- {
- /* For a frequency f, the period length is 10^9 / (279.365 * s * f). Here s
- * is the length of the waveform sample (SAMPLELENGTH).
- * So we need to compute 10^9 / (279.365 * s * (440 * 2^(n/12)))
- * == 2^(-n/12) * 10^9 / (279.365 * 440 * s)
- * == 2^(-n/12) * 10^9 / (122920.6 * s)
- */
- return (UWORD)(pow((double)2,-sliderpos/(double)12) *
- ((double)10000000 / (1229.206 * SAMPLELENGTH)));
- }
-
-
- /* PeriodToSlider():
- * Inverse of SliderToPeriod(). Takes a period length as an argument and
- * computes the appropriate slider position (between -5*12 and 4*12). This
- * function can afford to be slow because it's only ever called when the prefs
- * window pops up.
- */
- WORD PeriodToSlider(const UWORD period)
- {
- /* Since the period number p can be computed from slider position n by
- * p = 10^9 / (279.365 * 440 * s * 2^(n/12)) <==>
- * 2^(n/12) = 10^9 / (279.365 * 440 * s * p) <==>
- * n/12 = 2log(10^9 / (279.365 * 440 * s * p)) <==>
- * n = 12 * 2log(10^9 / (279.365 * 440 * s * p)) ==
- * 12 * 2log(10^9 / (122920.6 * s * p)) ==
- * 12 * ln(10^9 / (122920.6 * s * p)) / ln(2)
- */
- return (WORD)(12 * log(
- (double)1000000000 / (122920.6*SAMPLELENGTH*period)
- )/log((double)2));
- }
-
-